package com.smart.tool.log.impl;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import com.smart.tool.core.NetTool;
import com.smart.tool.log.LoggerFormatter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.helpers.Util;

/**
 * @Author gao.gwq
 * @Version StrategyLoggerFormatter.java, v 0.1 2023年11月28日 20:33 gao.gwq
 * @Description: TODO
 */
public class DefaultLoggerFormatter implements LoggerFormatter {

    private static final String FIELD_SEPARATOR = "|";
    private static final String LEFT_FIELD_SEPARATOR = "[[";

    private static final String RIGHT_FIELD_SEPARATOR = "]]";
    private static final String SEPARATOR = ",";

    @Override
    public String format(String domainType, String business, String bizId, String businessKeyFromat, String[] paramValues, String params,
        String businessReturn) {
        StringBuilder message = new StringBuilder();
        message.append(LEFT_FIELD_SEPARATOR).append(StringUtils.trimToEmpty(String.valueOf(domainType))).append(RIGHT_FIELD_SEPARATOR);
        message.append(LEFT_FIELD_SEPARATOR).append(StringUtils.trimToEmpty(bizId)).append(RIGHT_FIELD_SEPARATOR);
        message.append(LEFT_FIELD_SEPARATOR).append(NetTool.getLocalHost()).append(RIGHT_FIELD_SEPARATOR);
        message.append(LEFT_FIELD_SEPARATOR).append(StringUtils.trimToEmpty(business)).append(RIGHT_FIELD_SEPARATOR);
        String businessParameterStr = businessKey(businessKeyFromat, paramValues);

        message.append(LEFT_FIELD_SEPARATOR).append(businessParameterStr).append(RIGHT_FIELD_SEPARATOR);

        message.append(LEFT_FIELD_SEPARATOR).append(params).append(RIGHT_FIELD_SEPARATOR);
        message.append(LEFT_FIELD_SEPARATOR);
        if (StringUtils.isNotBlank(businessReturn)) {
            message.append(StringUtils.trimToEmpty(businessReturn).replaceAll("\\p{C}", ""));
        } else {
            message.append("--");
        }
        message.append(RIGHT_FIELD_SEPARATOR);
        String str = message.toString();
        return str;
    }

    private String businessKey(String businessKeyFormat, String[] businessParameter) {

        return arrayFormatNew(businessKeyFormat, businessParameter,"{}").replaceAll("\\p{C}", "");
    }

    private static String appendBusinessParameter(String[] businessParameter) {
        StringBuilder message = new StringBuilder("");
        if (null != businessParameter && businessParameter.length > 0) {
            for (int i = 0; i < businessParameter.length; i++) {
                message.append(StringUtils.trimToEmpty(businessParameter[i]));
                if (i != businessParameter.length - 1) {
                    message.append(SEPARATOR);
                }
            }
        }
        return message.toString();
    }

    /**
     * 如果存在占位符 则填充，如果不存在
     * @param messagePattern
     * @param businessParameter
     * @return
     */
    public static final String arrayFormatNew(String messagePattern, String[] businessParameter,String placeholder) {
        if (StringUtils.isBlank(messagePattern)) {
            return "";
        }
        if (businessParameter == null || businessParameter.length == 0) {
            return messagePattern;
        }
        int i = 0;
        StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
        int index = messagePattern.indexOf(placeholder);
        if (index == -1) {
            sbuf.append(messagePattern, i, messagePattern.length());
            return sbuf.toString();
        }
        int order = 0;
        for (; order < businessParameter.length; ++order) {

            int j = messagePattern.indexOf(placeholder, i);
            if (j == -1) {
                sbuf.append(messagePattern, i, messagePattern.length());
                break;
            }
            if (isEscapedDelimeter(messagePattern, j)) {
                if (!isDoubleEscaped(messagePattern, j)) {
                    --order;
                    sbuf.append(messagePattern, i, j - 1);
                    sbuf.append('{');
                    i = j + 1;
                } else {
                    sbuf.append(messagePattern, i, j - 1);
                    deeplyAppendParameter(sbuf, businessParameter[order], new HashMap());
                    i = j + 2;
                }
            } else {
                sbuf.append(messagePattern, i, j);
                deeplyAppendParameter(sbuf, businessParameter[order], new HashMap());
                i = j + 2;
            }
        }
        sbuf.append(messagePattern, i, messagePattern.length());
        return sbuf.toString();
    }

    public static final String arrayFormat(String messagePattern, String[] businessParameter) {
        if (messagePattern == null && (businessParameter == null || businessParameter.length == 0)) {
            return "";
        }
        if (messagePattern == null && businessParameter != null) {
            return appendBusinessParameter(businessParameter);
        }
        if (messagePattern != null && businessParameter == null) {
            return messagePattern;
        }

        int i = 0;
        StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
        int index = messagePattern.indexOf("{}");
        if (index == -1) {
            sbuf.append(messagePattern, i, messagePattern.length()).append(SEPARATOR);
            sbuf.append(appendBusinessParameter(businessParameter));
            return sbuf.toString();
        }
        int order = 0;
        for (; order < businessParameter.length; ++order) {

            int j = messagePattern.indexOf("{}", i);
            if (j == -1) {
                sbuf.append(messagePattern, i, messagePattern.length());
                break;
            }
            if (isEscapedDelimeter(messagePattern, j)) {
                if (!isDoubleEscaped(messagePattern, j)) {
                    --order;
                    sbuf.append(messagePattern, i, j - 1);
                    sbuf.append('{');
                    i = j + 1;
                } else {
                    sbuf.append(messagePattern, i, j - 1);
                    deeplyAppendParameter(sbuf, businessParameter[order], new HashMap());
                    i = j + 2;
                }
            } else {
                sbuf.append(messagePattern, i, j);
                deeplyAppendParameter(sbuf, businessParameter[order], new HashMap());
                i = j + 2;
            }
        }
        sbuf.append(messagePattern, i, messagePattern.length());
        if (order < businessParameter.length) {
            String[] subBusinessParameter = Arrays.asList(businessParameter).subList(order, businessParameter.length).toArray(
                new String[0]);
            sbuf.append(appendBusinessParameter(subBusinessParameter));
        }
        return sbuf.toString();
    }

    static final boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) {
        if (delimeterStartIndex == 0) {
            return false;
        } else {
            char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
            return potentialEscape == '\\';
        }
    }

    static final boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {
        return delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == '\\';
    }

    private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) {
        if (o == null) {
            sbuf.append("null");
        } else {
            if (!o.getClass().isArray()) {
                safeObjectAppend(sbuf, o);
            } else if (o instanceof boolean[]) {
                booleanArrayAppend(sbuf, (boolean[])((boolean[])o));
            } else if (o instanceof byte[]) {
                byteArrayAppend(sbuf, (byte[])((byte[])o));
            } else if (o instanceof char[]) {
                charArrayAppend(sbuf, (char[])((char[])o));
            } else if (o instanceof short[]) {
                shortArrayAppend(sbuf, (short[])((short[])o));
            } else if (o instanceof int[]) {
                intArrayAppend(sbuf, (int[])((int[])o));
            } else if (o instanceof long[]) {
                longArrayAppend(sbuf, (long[])((long[])o));
            } else if (o instanceof float[]) {
                floatArrayAppend(sbuf, (float[])((float[])o));
            } else if (o instanceof double[]) {
                doubleArrayAppend(sbuf, (double[])((double[])o));
            } else {
                objectArrayAppend(sbuf, (Object[])((Object[])o), seenMap);
            }

        }
    }

    private static void safeObjectAppend(StringBuilder sbuf, Object o) {
        try {
            String oAsString = o.toString();
            sbuf.append(oAsString);
        } catch (Throwable var3) {
            Util.report("SLF4J: Failed toString() invocation on an object of type [" + o.getClass().getName() + "]", var3);
            sbuf.append("[FAILED toString()]");
        }

    }

    private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) {
        sbuf.append('[');
        if (!seenMap.containsKey(a)) {
            seenMap.put(a, (Object)null);
            int len = a.length;

            for (int i = 0; i < len; ++i) {
                deeplyAppendParameter(sbuf, a[i], seenMap);
                if (i != len - 1) {
                    sbuf.append(", ");
                }
            }

            seenMap.remove(a);
        } else {
            sbuf.append("...");
        }

        sbuf.append(']');
    }

    private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {
        sbuf.append('[');
        int len = a.length;

        for (int i = 0; i < len; ++i) {
            sbuf.append(a[i]);
            if (i != len - 1) {
                sbuf.append(", ");
            }
        }

        sbuf.append(']');
    }

    private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {
        sbuf.append('[');
        int len = a.length;

        for (int i = 0; i < len; ++i) {
            sbuf.append(a[i]);
            if (i != len - 1) {
                sbuf.append(", ");
            }
        }

        sbuf.append(']');
    }

    private static void charArrayAppend(StringBuilder sbuf, char[] a) {
        sbuf.append('[');
        int len = a.length;

        for (int i = 0; i < len; ++i) {
            sbuf.append(a[i]);
            if (i != len - 1) {
                sbuf.append(", ");
            }
        }

        sbuf.append(']');
    }

    private static void shortArrayAppend(StringBuilder sbuf, short[] a) {
        sbuf.append('[');
        int len = a.length;

        for (int i = 0; i < len; ++i) {
            sbuf.append(a[i]);
            if (i != len - 1) {
                sbuf.append(", ");
            }
        }

        sbuf.append(']');
    }

    private static void intArrayAppend(StringBuilder sbuf, int[] a) {
        sbuf.append('[');
        int len = a.length;

        for (int i = 0; i < len; ++i) {
            sbuf.append(a[i]);
            if (i != len - 1) {
                sbuf.append(", ");
            }
        }

        sbuf.append(']');
    }

    private static void longArrayAppend(StringBuilder sbuf, long[] a) {
        sbuf.append('[');
        int len = a.length;

        for (int i = 0; i < len; ++i) {
            sbuf.append(a[i]);
            if (i != len - 1) {
                sbuf.append(", ");
            }
        }

        sbuf.append(']');
    }

    private static void floatArrayAppend(StringBuilder sbuf, float[] a) {
        sbuf.append('[');
        int len = a.length;

        for (int i = 0; i < len; ++i) {
            sbuf.append(a[i]);
            if (i != len - 1) {
                sbuf.append(", ");
            }
        }

        sbuf.append(']');
    }

    private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {
        sbuf.append('[');
        int len = a.length;

        for (int i = 0; i < len; ++i) {
            sbuf.append(a[i]);
            if (i != len - 1) {
                sbuf.append(", ");
            }
        }

        sbuf.append(']');
    }
}